﻿using System;
using System.Threading.Tasks;

namespace Innovative.Atom.Timer.Event
{
	public sealed class AtomIntervalEvent : AtomEvent
	{
		private TimeSpan _interval = TimeSpan.Zero;
		private long _maximumEvents = 0;

		#region Constructors
		public AtomIntervalEvent(TimeSpan interval, Task<bool> eventTask)
			: base(eventTask)
		{
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(DateTime startDateTime, TimeSpan interval, Task<bool> eventTask)
			: base(eventTask)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(DateTime startDateTime, TimeSpan interval, long maximumEvents, Task<bool> eventTask)
			: base(eventTask)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
			this.MaximumEvents = maximumEvents;
		}

		public AtomIntervalEvent(string eventName, TimeSpan interval, Task<bool> eventTask)
			: base(eventName, eventTask)
		{
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(string eventName, DateTime startDateTime, TimeSpan interval, Task<bool> eventTask)
			: base(eventName, eventTask)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(string eventName, DateTime startDateTime, TimeSpan interval, long maximumEvents, Task<bool> eventTask)
			: base(eventName, eventTask)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
			this.MaximumEvents = maximumEvents;
		}

		public AtomIntervalEvent(TimeSpan interval)
			: base()
		{
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(DateTime startDateTime, TimeSpan interval)
			: base()
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(DateTime startDateTime, TimeSpan interval, long maximumEvents)
			: base()
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
			this.MaximumEvents = maximumEvents;
		}

		public AtomIntervalEvent(string eventName, TimeSpan interval)
			: base(eventName)
		{
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(string eventName, DateTime startDateTime, TimeSpan interval)
			: base(eventName)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
		}

		public AtomIntervalEvent(string eventName, DateTime startDateTime, TimeSpan interval, long maximumEvents)
			: base(eventName)
		{
			this.CreatedDateTime = startDateTime;
			this.EventInterval = interval;
			this.MaximumEvents = maximumEvents;
		}
		#endregion

		public TimeSpan EventInterval
		{
			get
			{
				return _interval;
			}
			set
			{
				_interval = value;
			}
		}

		public long MaximumEvents
		{
			get
			{
				return _maximumEvents;
			}
			set
			{
				_maximumEvents = value;
			}
		}

		protected override void OnInitializeNextEventDateTime()
		{
			// ***
			// *** Calculate the initial event date and time
			// ***
			this.EventDateTime = this.CreatedDateTime.Add(this.EventInterval);
		}

		protected override void OnUpdateNextEventDateTime()
		{
			// ***
			// *** When MaximumEvents is 0 the events are
			// *** unlimited.
			// ***
			if ((this.MaximumEvents == 0) || (this.EventId <= this.MaximumEvents))
			{
				// ***
				// *** Calculate the amount of time for the
				// *** next event
				// ***
				TimeSpan nextDueTime = TimeSpan.FromSeconds(this.EventInterval.TotalSeconds * this.EventId);

				// ***
				// *** Calculate the next event date and time
				// ***
				this.EventDateTime = this.CreatedDateTime.Add(nextDueTime);
			}
			else
			{
				// ***
				// *** 
				// ***
				this.TaskIsExpired = true;
			}
		}
	}
}
